#include "websocket_server.h"

// Define a callback to handle new connection income
void on_new_connection(WebsocketServer* s, websocketpp::connection_hdl hdl){
    std::cout << "on new connection\r\n";
    WsServer::connection_ptr con = s->m_server->get_con_from_hdl(hdl);
    auto socket = con->get_raw_socket().native_handle();
    s->m_clients[socket] = hdl;
    auto addr = con->get_socket().remote_endpoint().address();
    auto host = con->get_host();
    auto uri = con->get_uri();
    auto resource = con->get_resource();
    std::cout<<socket << " "<<addr<<"  "<< host<<" "<<uri<<" "<<resource<<"\r\n";

}

// Define a callback to handle incoming messages
void on_connection_close(WebsocketServer* s, websocketpp::connection_hdl hdl){
    std::cout<<"connection closed\\r\n";
    WsServer::connection_ptr con = s->m_server->get_con_from_hdl(hdl);
    auto socket = con->get_raw_socket().native_handle();
    s->m_clients.erase(socket);
}

// Define a callback to handle incoming messages
void on_message(WebsocketServer* s, websocketpp::connection_hdl hdl, message_ptr msg) {
    std::cout << "on_message called with hdl: " << hdl.lock().get()
              << " and message: " << msg->get_payload()
              << std::endl;

    // check for a special command to instruct the server to stop listening so
    // it can be cleanly exited.
    if (msg->get_payload() == "stop-listening") {
        s->m_server->stop_listening();
        return;
    }
    try {
        s->m_server->send(hdl, msg->get_payload(), msg->get_opcode());

    } catch (websocketpp::exception const & e) {
        std::cout << "Echo failed because: "
                  << "(" << e.what() << ")" << std::endl;
    }
}

WebsocketServer::WebsocketServer(std::string server,uint32_t port){
    m_port = port;
    m_server = new WsServer;
    m_thread = new std::thread([this](){
        // Set logging settings
        m_server->set_access_channels(websocketpp::log::alevel::all);
        m_server->clear_access_channels(websocketpp::log::alevel::frame_payload);
        // Initialize Asio
        m_server->init_asio();
        // Register our message handler
        m_server->set_open_handler(std::bind(&on_new_connection,this,::_1));
        m_server->set_message_handler(std::bind(&on_message,this,::_1,::_2));
        m_server->set_close_handler(std::bind(&on_connection_close,this,::_1));
        m_server->listen(m_port);
        // Start the server accept loop
        m_server->start_accept();
        // Start the ASIO io_service run loop
        m_server->run();
    });
}

int WebsocketServer::SendData(uint32_t fd,const char* dat,int len,
    websocketpp::frame::opcode::value op){

    auto itr = this->m_clients.find(fd);
    if(itr != m_clients.end()){
        std::error_code err;
        WsServer::connection_ptr con = m_server->get_con_from_hdl(itr->second);
        m_server->send(itr->second,dat,len,op,err);
        if(err.message() != ""){
            std::cout<<"websocket error" << err.message()<<std::endl;
            return -1;
        }
    }
    return 0;
}

int WebsocketServer::SendDataAllClient(const char* dat,int len,
    websocketpp::frame::opcode::value opcode){

    for(auto itr = m_clients.begin();itr != m_clients.end();itr++){
        std::error_code err;
        WsServer::connection_ptr con = m_server->get_con_from_hdl(itr->second);
        m_server->send(itr->second,dat,len, opcode,err);
        if(err.message() != ""){
            std::cout<<"websocket error" << err.message()<<std::endl;
            return -1;
        }
    }
    return 0;
}

